home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
User's Choice Windows CD
/
User's Choice Windows CD (CMS Software)(1993).iso
/
misc1
/
iv26_w30.zip
/
SOURCES
/
BUTTON.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-12-21
|
15KB
|
669 lines
/*
* Copyright (c) 1987, 1988, 1989 Stanford University
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided
* that the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Stanford not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. Stanford makes no representations about
* the suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*
* STANFORD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
* IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* Button management.
*/
#ifdef _3D
#include <InterViews/color.h>
#endif
#include <InterViews/bitmap.h>
#include <InterViews/button.h>
#include <InterViews/font.h>
#include <InterViews/painter.h>
#include <InterViews/pattern.h>
#include <InterViews/sensor.h>
#include <InterViews/shape.h>
#include <InterViews/subject.h>
#include <InterViews/Bitmaps/radiob.bm>
#include <InterViews/Bitmaps/radioc.bm>
#include <InterViews/Bitmaps/radioh.bm>
#include <InterViews/Bitmaps/radiom.bm>
#include <InterViews/Bitmaps/radio.bm>
static const int sep = 3;
static const int pad = 4;
inline int HalfRadioButtonSize (int h) { return round(.4*h); }
inline int HalfCheckBoxSize (int h) { return round(.4*h); }
/*
* A button state is a value that is settable from one or more buttons.
* When the state is modified, it updates all its buttons.
*/
ButtonState::ButtonState () {
value = nil;
Reference();
}
ButtonState::ButtonState (int v) {
value = (void*)v;
Reference();
}
ButtonState::ButtonState (void* v) {
value = v;
Reference();
}
void ButtonState::SetValue (int v) {
Modify((void*)v);
}
void ButtonState::SetValue (void* v) {
Modify(v);
}
void ButtonState::operator= (ButtonState& s) {
Modify(s.value);
}
void ButtonState::Modify (void* v) {
if (value != v) {
value = v;
Notify();
}
}
/*
* Simple list of buttons.
*/
class ButtonList {
public:
Button* cur;
ButtonList* next;
ButtonList (Button* b) { cur = b; next = nil; }
};
static void Remove (ButtonList*& blist, Button* b) {
register ButtonList* bl;
register ButtonList* prev;
prev = nil;
for (bl = blist; bl != nil; bl = bl->next) {
if (bl->cur == b) {
if (prev == nil) {
blist = bl->next;
} else {
prev->next = bl->next;
}
delete bl;
break;
}
prev = bl;
}
}
static void DeleteList (ButtonList* blist) {
register ButtonList* bl;
register ButtonList* next;
for (bl = blist; bl != nil; bl = next) {
next = bl->next;
delete bl;
}
}
/*
* A button has a ButtonState subject that it modifies when pressed.
* Also, a button may have associated buttons that are enabled/disabled
* when it is chosen/unchosen.
*/
Button::Button (ButtonState* s, void* v) {
Init(s, v);
}
Button::Button (const char* name, ButtonState* s, void* v) {
SetInstance(name);
Init(s, v);
}
Button::Button (Painter* out, ButtonState* s, void* v) : (nil, out) {
Init(s, v);
}
void Button::Init (ButtonState* s, void* v) {
SetClassName("Button");
value = v;
subject = s;
associates = nil;
enabled = true;
hit = false;
subject->Attach(this);
Update();
input = new Sensor(updownEvents);
input->Catch(EnterEvent);
input->Catch(LeaveEvent);
}
Button::~Button () {
if (subject != nil) {
subject->Detach(this);
}
DeleteList(associates);
}
void Button::Attach (Button* b) {
ButtonList* head;
head = new ButtonList(b);
head->next = associates;
associates = head;
if (chosen) {
b->Enable();
} else {
b->Disable();
}
}
void Button::Detach (Button* b) {
Remove(associates, b);
}
void Button::Enable () {
if (!enabled) {
enabled = true;
if (canvas != nil) {
Draw();
}
}
}
void Button::Disable () {
if (enabled) {
enabled = false;
if (canvas != nil) {
Draw();
}
}
}
void Button::Choose () {
register ButtonList* bl;
if (!chosen) {
chosen = true;
if (enabled) {
if (canvas != nil) {
Refresh();
}
for (bl = associates; bl != nil; bl = bl->next) {
bl->cur->Enable();
}
}
}
}
void Button::UnChoose () {
register ButtonList* bl;
if (chosen) {
chosen = false;
if (enabled) {
if (canvas != nil) {
Refresh();
}
for (bl = associates; bl != nil; bl = bl->next) {
bl->cur->Disable();
}
}
}
}
void Button::SetDimensions (int width, int height) {
shape->width = width;
shape->height = height;
shape->Rigid();
}
void Button::Refresh () {
/* default shouldn't happen */
}
void Button::Handle (register Event& e) {
if (e.eventType == DownEvent && e.target == this) {
boolean inside = true;
do {
if (enabled && e.target == this) {
if (e.eventType == EnterEvent) {
inside = true;
} else if (e.eventType == LeaveEvent) {
inside = false;
}
if (inside) {
if (!hit) {
hit = true;
Refresh();
}
} else {
if (hit) {
hit = false;
Refresh();
}
}
}
Read(e);
} while (e.eventType != UpEvent);
if (hit) {
hit = false;
Refresh();
}
if (enabled && inside) {
Press();
}
}
}
void Button::Press () {
if (subject != nil) {
subject->SetValue(value);
} else {
Refresh();
}
}
void Button::Update () {
void* v;
subject->GetValue(v);
if (!chosen && value == v) {
Choose();
} else if (chosen && value != v) {
UnChoose();
}
}
TextButton::TextButton (const char* str, ButtonState* s, void* v) : (s, v) {
Init(str);
}
TextButton::TextButton (
const char* name, const char* str, ButtonState* s, void* v
) : (name, s, v) {
Init(str);
}
TextButton::TextButton (
const char* str, ButtonState* s, void* v, Painter* out
) : (out, s, v) {
Init(str);
}
void TextButton::Init (const char* str) {
SetClassName("TextButton");
text = str;
background = nil;
grayout = nil; }
void TextButton::MakeBackground () {
Unref(background);
background = new Painter(output);
background->Reference();
background->SetColors(output->GetBgColor(), output->GetFgColor());
Unref(grayout);
grayout = new Painter(background);
grayout->Reference();
grayout->SetPattern(gray);
grayout->FillBg(false);
}
void TextButton::MakeShape () {
if (text != nil) {
Font* f = output->GetFont();
shape->width += f->Width(text);
shape->height += f->Height();
}
shape->Rigid();
}
TextButton::~TextButton () {
Unref(background);
Unref(grayout);
}
PushButton::PushButton (
const char* str, ButtonState* s, int v
) : (str, s, (void*)v) {
Init();
}
PushButton::PushButton (
const char* str, ButtonState* s, void* v
) : (str, s, v) {
Init();
}
PushButton::PushButton (
const char* name, const char* str, ButtonState* s, int v
) : (name, str, s, (void*)v) {
Init();
}
PushButton::PushButton (
const char* name, const char* str, ButtonState* s, void* v
) : (name, str, s, v) {
Init();
}
PushButton::PushButton (
const char* str, ButtonState* s, int v, Painter* out
) : (str, s, (void*)v, out) {
Init();
}
PushButton::PushButton (
const char* str, ButtonState* s, void* v, Painter* out
) : (str, s, v, out) {
Init();
}
void PushButton::Init () {
SetClassName("PushButton");
}
void PushButton::Reconfig () {
MakeBackground();
if (shape->Undefined()) {
MakeShape();
shape->width += output->GetFont()->Width(" ");
shape->height += 2*pad;
}
}
void PushButton::Redraw (Coord x1, Coord y1, Coord x2, Coord y2) {
output->ClearRect(canvas, x1, y1, x2, y2);
Refresh();
}
void PushButton::Refresh () {
#ifndef _3D
register int r;
Coord x[16], y[16];
Coord tx, ty;
r = min(10*pixels, min(xmax+1, ymax+1)/6);
x[0] = 0; y[0] = r;
x[1] = 0; y[1] = r + r;
x[2] = 0; y[2] = ymax - r - r;
x[3] = 0; y[3] = ymax - r;
x[4] = r; y[4] = ymax;
x[5] = r + r; y[5] = ymax;
x[6] = xmax - r - r; y[6] = ymax;
x[7] = xmax - r; y[7] = ymax;
x[8] = xmax; y[8] = ymax - r;
x[9] = xmax; y[9] = ymax - r - r;
x[10] = xmax; y[10] = r + r;
x[11] = xmax; y[11] = r;
x[12] = xmax - r; y[12] = 0;
x[13] = xmax - r - r; y[13] = 0;
x[14] = r + r; y[14] = 0;
x[15] = r; y[15] = 0;
tx = (xmax - output->GetFont()->Width(text))/2;
ty = pad;
if (chosen || hit) {
output->FillBSpline(canvas, x, y, 16);
background->Text(canvas, text, tx, ty);
} else {
background->FillRect(canvas, 0, 0, xmax, ymax);
output->ClosedBSpline(canvas, x, y, 16);
output->Text(canvas, text, tx, ty);
}
if (!enabled) {
grayout->FillRect(canvas, 0, 0, xmax, ymax);
}
#endif
#ifdef _3D
Coord tx, ty;
tx = (xmax - output3D->GetFont()->Width(text))/2;
ty = pad;
if (chosen || hit) // Button wurde gedrueckt
{ output3D->Border(canvas,false);
output3D->InvertColors();
output3D->FillRect(canvas,2,2,xmax-2,ymax-2);
output3D->InvertColors();
output->Text(canvas, text, tx+1, ty+1); }
else
{ output3D->Border(canvas);
output->Text(canvas, text, tx, ty); }
if (!enabled)
{ grayout->FillRect(canvas, 0, 0, xmax, ymax); }
#endif
}
static Bitmap* radioMask;
static Bitmap* radioPlain;
static Bitmap* radioHit;
static Bitmap* radioChosen;
static Bitmap* radioBoth;
RadioButton::RadioButton (
const char* str, ButtonState* s, int v
) : (str, s, (void*)v) {
Init();
}
RadioButton::RadioButton (
const char* str, ButtonState* s, void* v
) : (str, s, v) {
Init();
}
RadioButton::RadioButton (
const char* name, const char* str, ButtonState* s, int v
) : (name, str, s, (void*)v) {
Init();
}
RadioButton::RadioButton (
const char* name, const char* str, ButtonState* s, void* v
) : (name, str, s, v) {
Init();
}
RadioButton::RadioButton (
const char* str, ButtonState* s, int v, Painter* out
) : (str, s, (void*)v, out) {
Init();
}
RadioButton::RadioButton (
const char* str, ButtonState* s, void* v, Painter* out
) : (str, s, v, out) {
Init();
}
void RadioButton::Init () {
SetClassName("RadioButton");
}
void RadioButton::Reconfig () {
MakeBackground();
if (shape->Undefined()) {
MakeShape();
shape->width += shape->height + sep;
}
if (radioMask == nil) {
radioMask = new Bitmap(
radio_mask_bits, radio_mask_width, radio_mask_height
);
radioMask->Reference();
radioPlain = new Bitmap(
radio_plain_bits, radio_plain_width, radio_plain_height
);
radioPlain->Reference();
radioHit = new Bitmap(
radio_hit_bits, radio_hit_width, radio_hit_height
);
radioHit->Reference();
radioChosen = new Bitmap(
radio_chosen_bits, radio_chosen_width, radio_chosen_height
);
radioChosen->Reference();
radioBoth = new Bitmap(
radio_both_bits, radio_both_width, radio_both_height
);
radioBoth->Reference();
}
}
void RadioButton::Redraw (Coord x1, Coord y1, Coord x2, Coord y2) {
int h = output->GetFont()->Height();
int r = radio_plain_width;
output->ClearRect(canvas, x1, y1, x2, y2);
Coord tx = r + sep;
Coord ty = (ymax + 1 - h) / 2;
output->Text(canvas, text, tx, ty);
Refresh();
}
void RadioButton::Refresh () {
Coord x = 0;
Coord y = (ymax+1 - radio_plain_height)/2;
if (!hit && !chosen) {
output->Stencil(canvas, x, y, radioPlain, radioMask);
} else if (hit && !chosen) {
output->Stencil(canvas, x, y, radioHit, radioMask);
} else if (!hit && chosen) {
output->Stencil(canvas, x, y, radioChosen, radioMask);
} else if (hit && chosen) {
output->Stencil(canvas, x, y, radioBoth, radioMask);
}
if (!enabled) {
grayout->FillRect(canvas, 0, 0, xmax, ymax);
}
}
CheckBox::CheckBox (
const char* str, ButtonState* s, int on, int off
) : (str, s, (void*)on) {
Init((void*)off);
}
CheckBox::CheckBox (
const char* str, ButtonState* s, void* on, void* off
) : (str, s, on) {
Init(off);
}
CheckBox::CheckBox (
const char* name, const char* str, ButtonState* s, int on, int off
) : (name, str, s, (void*)on) {
Init((void*)off);
}
CheckBox::CheckBox (
const char* name, const char* str, ButtonState* s, void* on, void* off
) : (name, str, s, on) {
Init(off);
}
CheckBox::CheckBox (
const char* str, ButtonState* s, int on, int off, Painter* out
) : (str, s, (void*)on, out) {
Init((void*)off);
}
CheckBox::CheckBox (
const char* str, ButtonState* s, void* on, void* off, Painter* out
) : (str, s, on, out) {
Init(off);
}
void CheckBox::Init (void* v) {
SetClassName("CheckBox");
offvalue = v;
}
void CheckBox::Reconfig () {
MakeBackground();
if (shape->Undefined()) {
MakeShape();
shape->width += shape->height + sep;
}
Update();
}
void CheckBox::Press () {
if (chosen) {
subject->GetValue(value);
subject->SetValue(offvalue);
} else {
subject->SetValue(value);
}
}
void CheckBox::Update () {
void* v;
subject->GetValue(v);
if (v != offvalue) {
Choose();
value = v;
} else {
UnChoose();
}
}
void CheckBox::Redraw (Coord x1, Coord y1, Coord x2, Coord y2) {
int h = output->GetFont()->Height();
int t = HalfCheckBoxSize(h);
output->ClearRect(canvas, x1, y1, x2, y2);
Coord tx = 2*t + sep;
Coord ty = (ymax + 1 - h) / 2;
output->Text(canvas, text, tx, ty);
Refresh();
}
void CheckBox::Refresh () {
int h = output->GetFont()->Height();
int t = HalfCheckBoxSize(h);
Coord cx = t;
Coord cy = (ymax + 1)/2;
Coord left = cx - t;
Coord right = cx + t;
Coord bottom = cy - t;
Coord top = cy + t;
output->Rect(canvas, left, bottom, right, top);
background->FillRect(canvas, left+1, bottom+1, right-1, top-1);
if (hit) {
output->Rect(canvas, left+1, bottom+1, right-1, top-1);
}
if (chosen) {
output->Line(canvas, left, bottom, right, top);
output->Line(canvas, left, top, right, bottom);
}
if (!enabled) {
grayout->FillRect(canvas, 0, 0, xmax, ymax);
}
}